/**********************************************************************
 * Copyright 2012 Consultingwerk Ltd.                                 *
 *                                                                    *
 * Licensed under the Apache License, Version 2.0 (the "License");    *
 * you may not use this file except in compliance with the License.   *
 * You may obtain a copy of the License at                            *
 *                                                                    *
 *     http://www.apache.org/licenses/LICENSE-2.0                     *
 *                                                                    *
 * Unless required by applicable law or agreed to in writing,         *
 * software distributed under the License is distributed on an        * 
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,       *
 * either express or implied. See the License for the specific        *
 * language governing permissions and limitations under the License.  *
 *                                                                    *
 **********************************************************************/
/*------------------------------------------------------------------------
    File        : ClassDocumentationParser
    Purpose     : 
    Syntax      : 
    Description : 
    Author(s)   : Mike Fechner / Consultingwerk Ltd.
    Created     : Mon Sep 10 17:53:07 CEST 2012
    Notes       : 
  ----------------------------------------------------------------------*/

ROUTINE-LEVEL ON ERROR UNDO, THROW.

USING Consultingwerk.Studio.* FROM PROPATH . 
USING Consultingwerk.Util.*   FROM PROPATH .  
USING Progress.Lang.*         FROM PROPATH .

CLASS Consultingwerk.Studio.ClassDocumentation.ClassDocumentationParser
    IMPLEMENTS Consultingwerk.ISaxReader: 

    DEFINE VARIABLE hSaxHandler          AS HANDLE    NO-UNDO .
    DEFINE VARIABLE lcCharacterData      AS LONGCHAR  NO-UNDO . 
    DEFINE VARIABLE iInterfaceSequence   AS INTEGER   NO-UNDO .
    DEFINE VARIABLE iParameterSequence   AS INTEGER   NO-UNDO .
    DEFINE VARIABLE iUsingSequence       AS INTEGER   NO-UNDO . 
    DEFINE VARIABLE cParameterParentGUID AS CHARACTER NO-UNDO .
    DEFINE VARIABLE lExpectingCharacter  AS LOGICAL   NO-UNDO INIT FALSE .
    
    { Consultingwerk/Studio/ClassDocumentation/dsClassDocumentation.i &REFERENCE-ONLY=REFERENCE-ONLY }

    /*------------------------------------------------------------------------------
        Purpose: Constructor for the ClassDocumentionParser class
        Notes:   
    ------------------------------------------------------------------------------*/
    CONSTRUCTOR PUBLIC ClassDocumentationParser ():
        SUPER ().

        RUN Consultingwerk/sax-reader-handler.p 
            PERSISTENT SET hSaxHandler (THIS-OBJECT) .

    END CONSTRUCTOR.

    /*------------------------------------------------------------------------------
        Purpose: Parses a class doc XML document generated by PCT
        Notes:   
        @param pcFileName Description
        @param dsClassDocumentation OUTPUT The dataset with the raw class documentation (pass in BY-REFERENCE)
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC VOID ParseClassDocumentation (pcFileName AS CHARACTER,
                                                INPUT-OUTPUT DATASET dsClassDocumentation):

        DEFINE VARIABLE hSaxReader AS HANDLE NO-UNDO.
        
        DATASET dsClassDocumentation:EMPTY-DATASET () . 
        
        FILE-INFO:FILE-NAME = pcFileName . 
        IF FILE-INFO:FULL-PATHNAME = ? THEN 
            UNDO, THROW NEW AppError (SUBSTITUTE ("Invalid file for parsing: &1":U, 
                                                  pcFileName),
                                      0) .
        
        CREATE SAX-READER hSaxReader . 
        hSaxReader:HANDLER = hSaxHandler . 

        hSaxReader:SET-INPUT-SOURCE ("FILE":U, pcFileName).
        
        hSaxReader:SAX-PARSE () .                

        FINALLY:
            IF VALID-HANDLE (hSaxReader) THEN 
                DELETE OBJECT hSaxReader . 
        END FINALLY.

    END METHOD .

    /*------------------------------------------------------------------------------
        Purpose: Invoked when the XML parser detects character data.                                                                      
        Notes:   The parser calls this method to report each chunk of character data. 
                 It might report contiguous character data in one chunk, or split it 
                 into several chunks. If validation is enabled, whitespace is reported 
                 by the IgnorableWhitespace callback                                                                      
        @param plcCharData A LONGCHAR that contains a chunk of character data.
        @param piNumChars The number of characters contained in the MEMPTR.
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC VOID SaxCharacters (plcCharData AS LONGCHAR,
                                      piNumChars  AS INTEGER):
        
        IF lExpectingCharacter THEN 
            ASSIGN lcCharacterData = lcCharacterData + plcCharData .

    END METHOD .

    /*------------------------------------------------------------------------------
        Purpose: Invoked when the XML parser detects the end of an XML document.                                                                     
        Notes:                                                                        
        @param pcNamespaceURI A character string indicating the namespace URI of the element. If namespace processing is not enabled or the element is not part of a namespace, the string is of length zero.
        @param pcLocalName A character string indicating the non-prefixed element name. If namespace processing is not enabled, the string is of length zero.
        @param pcName A character string indicating the actual name of the element in the XML source. If the name has a prefix, qName includes it, whether or not namespace processing is enabled.
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC VOID SaxEndElement (pcNamespaceURI AS CHARACTER,
                                      pcLocalName    AS CHARACTER, 
                                      pcName         AS CHARACTER):
        
        CASE pcName:
            WHEN "interfaces":U THEN 
                ASSIGN eInterfaces.InterfaceName = lcCharacterData
                       lcCharacterData           = "":U 
                       lExpectingCharacter       = FALSE .
            WHEN "classComment":U THEN 
                ASSIGN eUnit.ClassComment  = lcCharacterData 
                       lcCharacterData     = lcCharacterData + "~n":U 
                       lExpectingCharacter = FALSE.
            WHEN "constrComment":U THEN 
                ASSIGN eConstructor.ConstructorComment = lcCharacterData
                       lExpectingCharacter             = FALSE.  
            WHEN "comment":U THEN 
                ASSIGN eMethod.MethodComment = lcCharacterData
                       lExpectingCharacter             = FALSE.  
            WHEN "propertyComment":U THEN 
                ASSIGN eProperty.PropertyComment = lcCharacterData
                       lExpectingCharacter       = FALSE.  
            WHEN "eventComment":U THEN 
                ASSIGN eEvent.EventComment = lcCharacterData
                       lExpectingCharacter = FALSE.  
        END CASE . 

    END METHOD .

    /*------------------------------------------------------------------------------
        Purpose: Invoked when the XML parser detects the beginning of an element.                                                                     
        Notes:      
        @param pcNamespaceURI A character string indicating the namespace URI of the element. If namespace processing is not enabled or the element is not part of a namespace, the string is of length zero.
        @param pcLocalName A character string indicating the non-prefixed element name. If namespace processing is not enabled, the string is of length zero.
        @param pcName A character string indicating the actual name of the element in the XML source. If the name has a prefix, qName includes it, whether or not namespace processing is enabled.
        @param phAttributes A handle to a SAX-attributes object, which provides access to all attributes specified for the element. If the element has no attributes, attributes is still a valid handle, and the NUM-ITEMS attribute is zero.      
    ------------------------------------------------------------------------------*/
    METHOD PUBLIC VOID SaxStartElement (pcNamespaceURI AS CHARACTER,
                                        pcLocalName    AS CHARACTER,
                                        pcName         AS CHARACTER,
                                        phAttributes   AS HANDLE):
        
        IF pcName <> "unit":U AND NOT AVAILABLE eUnit THEN 
            UNDO, THROW NEW AppError (SUBSTITUTE ("Unable to parse element ~"&1~" as there is no ~"unit~" element.":U, pcName), 0) . 

        CASE pcName:
            WHEN "unit":U THEN DO:
                CREATE eUnit. 
                ASSIGN eUnit.GUID         = GUID 
                       iInterfaceSequence = 0 
                       lcCharacterData      = "":U .     
                
                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eUnit:HANDLE, phAttributes) .
            END.
            WHEN "interfaces":U THEN DO:
                CREATE eInterfaces .
                ASSIGN iInterfaceSequence   = iInterfaceSequence + 1
                       eInterfaces.UnitGUID = eUnit.GUID
                       eInterfaces.Sequence = iInterfaceSequence 
                       eInterfaces.GUID     = GUID 
                       lcCharacterData      = "":U
                       lExpectingCharacter  = TRUE .     
            END.
            WHEN "classComment":U OR WHEN "constrComment":U OR 
            WHEN "comment":U OR WHEN "propertyComment":U OR
            WHEN "eventComment":U THEN DO:
                ASSIGN lExpectingCharacter = TRUE . 
            END.
            WHEN "constructor":U THEN DO:
                CREATE eConstructor . 
                ASSIGN eConstructor.GUID    = GUID
                       iParameterSequence   = 0  
                       cParameterParentGUID = eConstructor.GUID 
                       lcCharacterData      = "":U .     

                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eConstructor:HANDLE, phAttributes) .
            END.
            WHEN "method":U THEN DO:
                CREATE eMethod . 
                ASSIGN eMethod.GUID         = GUID
                       iParameterSequence   = 0  
                       cParameterParentGUID = eMethod.GUID 
                       lcCharacterData      = "":U .     

                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eMethod:HANDLE, phAttributes) .
            END.
            WHEN "parameter":U THEN DO:
               CREATE eParameter . 
               ASSIGN iParameterSequence    = iParameterSequence + 1
                      eParameter.GUID       = GUID 
                      eParameter.ParentGUID = cParameterParentGUID
                      eParameter.Sequence   = iParameterSequence . 
               
                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eParameter:HANDLE, phAttributes) .
            END.
            WHEN "property":U THEN DO:
                CREATE eProperty . 
                ASSIGN eProperty.GUID         = GUID
                       lcCharacterData      = "":U .     

                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eProperty:HANDLE, phAttributes) .
            END.
            WHEN "event":U THEN DO:
                CREATE eEvent . 
                ASSIGN eEvent.GUID         = GUID
                       iParameterSequence   = 0  
                       cParameterParentGUID = eEvent.GUID 
                       lcCharacterData      = "":U .     

                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eEvent:HANDLE, phAttributes) .
            END.
            WHEN "using":U THEN DO:
                CREATE eUsing.
                ASSIGN iUsingSequence  = iUsingSequence + 1
                       eUsing.GUID     = GUID 
                       eUsing.UnitGUID = eUnit.GUID
                       eUsing.Sequence = iUsingSequence .
                
                BufferHelper:ParseSaxAttributesToBuffer (BUFFER eUsing:HANDLE, phAttributes) .
            END.                     
                                                    
            OTHERWISE
                UNDO, THROW NEW AppError (SUBSTITUTE ("Unrecognized element ~"&1~".":U, pcName), 0) .
        END CASE . 

    END METHOD .

    /*------------------------------------------------------------------------------
        Purpose: Destructor for the ClassDocumentationParser class                                                                      
        Notes:                                                                        
    ------------------------------------------------------------------------------*/
    DESTRUCTOR PUBLIC ClassDocumentationParser ():

        IF VALID-HANDLE (hSaxHandler) THEN 
            DELETE OBJECT hSaxHandler . 

    END DESTRUCTOR.

END CLASS.
